﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Printing;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows.Input;

namespace personalplaner.common.controls
{
	public class PrintControl : Control
	{
		static PrintControl()
        {
			DefaultStyleKeyProperty.OverrideMetadata(typeof(PrintControl), new FrameworkPropertyMetadata(typeof(PrintControl)));
			CommandManager.RegisterClassCommandBinding(typeof(PrintControl), new CommandBinding(PrintCommand, PrintCommand_Executed));
		}

		public PrintControl()
		{
			Loaded += new RoutedEventHandler(PrintControlLoaded);
		}

		void PrintControlLoaded(object sender, RoutedEventArgs e)
		{
			var printers = new List<PrintQueue>();

			var printServer = new LocalPrintServer();
			var printQueuesOnLocalServer = printServer.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Local, EnumeratedPrintQueueTypes.Connections });
			foreach (PrintQueue printer in printQueuesOnLocalServer)
			{
				printers.Add(printer);
			}

			Printers = printers;
		}

		#region Properties

		/// <summary>
		/// Gets or sets the name of the Document that will be printed
		/// </summary>
		public string DocumentName
		{
			get
			{
				return (string)GetValue(DocumentNameProperty);
			}
			set
			{
				SetValue(DocumentNameProperty, value);
			}
		}

		public static readonly DependencyProperty DocumentNameProperty =
			DependencyProperty.Register("DocumentName", typeof(string), typeof(PrintControl), new PropertyMetadata("Document"));

		
		public IEnumerable<UIElement> Pages
		{
			get
			{
				return (IEnumerable<UIElement>)GetValue(PagesProperty);
			}
			set
			{
				SetValue(PagesProperty, value);
			}
		}

		public static readonly DependencyProperty PagesProperty =
			DependencyProperty.Register("Pages", typeof(IEnumerable<UIElement>), typeof(PrintControl), new PropertyMetadata(null));
		
		public int Copies
		{
			get
			{
				return (int)GetValue(CopiesProperty);
			}
			set
			{
				SetValue(CopiesProperty, value);
			}
		}

		public static readonly DependencyProperty CopiesProperty =
			DependencyProperty.Register("Copies", typeof(int), typeof(PrintControl), new PropertyMetadata(1));

		public IEnumerable<PrintQueue> Printers
		{
			get
			{
				return (IEnumerable<PrintQueue>)GetValue(PrintersProperty);
			}
			internal set
			{
				SetValue(PrintersProperty, value);
			}
		}
		public static readonly DependencyProperty PrintersProperty =
			DependencyProperty.Register("Printers", typeof(IEnumerable<PrintQueue>), typeof(PrintControl), new PropertyMetadata(null, new PropertyChangedCallback(OnPrintersPropertyChanged)));

		private static void OnPrintersPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var printControl = (PrintControl)d;
			if (printControl != null)
				printControl.OnPrintersChanged((IEnumerable<PrintQueue>)e.OldValue, (IEnumerable<PrintQueue>)e.NewValue);
		}

		private void OnPrintersChanged(IEnumerable<PrintQueue> oldValue, IEnumerable<PrintQueue> newValue)
		{
			var dp = LocalPrintServer.GetDefaultPrintQueue();
			foreach (var pq in newValue)
			{
				if (pq.Name == dp.Name)
				{
					//SetValue(SelectedPrinterProperty, pq);
					SelectedPrinter = pq;
					break;
				}
			}
		}
		
		public PrintQueue SelectedPrinter
		{
			get
			{
				return (PrintQueue)GetValue(SelectedPrinterProperty);
			}
			set
			{
				SetValue(SelectedPrinterProperty, value);
			}
		}

		public static readonly DependencyProperty SelectedPrinterProperty =
			DependencyProperty.Register("SelectedPrinter", typeof(PrintQueue), typeof(PrintControl), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedPrinterPropertyChanged)));

		private static void OnSelectedPrinterPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var printControl = (PrintControl)d;
			if (printControl != null)
				printControl.OnSelectedPrinterChanged((PrintQueue)e.OldValue, (PrintQueue)e.NewValue);
		}

		private void OnSelectedPrinterChanged(PrintQueue oldValue, PrintQueue newValue)
		{
			//TODO: the paper orientation should be set globaly so that it can be changed
			// set the orientation to landscape
			// this is only temp fix and should be corrected
			SelectedPrinter.DefaultPrintTicket.PageOrientation = PageOrientation.Landscape;
			SelectedPrinter.CurrentJobSettings.CurrentPrintTicket.PageOrientation = PageOrientation.Landscape;

			if (SelectedPrinter.DefaultPrintTicket.PageOrientation == PageOrientation.Landscape)
			{
				PaperWidth = SelectedPrinter.DefaultPrintTicket.PageMediaSize.Height != null
				             	? (double) SelectedPrinter.DefaultPrintTicket.PageMediaSize.Height
				             	: double.NaN;
				PaperHeight = SelectedPrinter.DefaultPrintTicket.PageMediaSize.Width != null
				              	? (double) SelectedPrinter.DefaultPrintTicket.PageMediaSize.Width
				              	: double.NaN;
			}
			else
			{
				PaperWidth = SelectedPrinter.DefaultPrintTicket.PageMediaSize.Width != null
								? (double)SelectedPrinter.DefaultPrintTicket.PageMediaSize.Width
								: double.NaN;
				PaperHeight = SelectedPrinter.DefaultPrintTicket.PageMediaSize.Height != null
								? (double)SelectedPrinter.DefaultPrintTicket.PageMediaSize.Height
								: double.NaN;
			}

			RoutedPropertyChangedEventArgs<PrintQueue> args = new RoutedPropertyChangedEventArgs<PrintQueue>(oldValue, newValue);
			args.RoutedEvent = PrintControl.SelectedPrinterChangedEvent;
			RaiseEvent(args);
		}

		public double PaperWidth
		{
			get
			{
				return (double)GetValue(PaperWidthProperty);
			}
			set
			{
				SetValue(PaperWidthProperty, value);
			}
		}
		public static readonly DependencyProperty PaperWidthProperty =
			DependencyProperty.Register("PaperWidth", typeof(double), typeof(PrintControl), new PropertyMetadata(double.NaN));

		public double PaperHeight
		{
			get
			{
				return (double)GetValue(PaperHeightProperty);
			}
			set
			{
				SetValue(PaperHeightProperty, value);
			}
		}
		public static readonly DependencyProperty PaperHeightProperty =
			DependencyProperty.Register("PaperHeight", typeof(double), typeof(PrintControl), new PropertyMetadata(double.NaN));



		#endregion

		#region Events

		public static readonly RoutedEvent SelectedPrinterChangedEvent = EventManager.RegisterRoutedEvent("SelectedPrinterChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<PrintQueue>), typeof(PrintControl));
		public event RoutedPropertyChangedEventHandler<PrintQueue> SelectedPrinterChanged
		{
			add { AddHandler(SelectedPrinterChangedEvent, value); }
			remove { RemoveHandler(SelectedPrinterChangedEvent, value); }
		}

		#endregion //Events

		#region Printing

		public static readonly RoutedCommand PrintCommand = new RoutedCommand("Print", typeof(PrintControl));
		/// <summary>
		/// Event raised when the Show command is executed.
		/// </summary>
		private static void PrintCommand_Executed(object target, ExecutedRoutedEventArgs e)
		{
			var c = (PrintControl)target;
			c.Print();
		}

		public void Print()
		{
			//http://www.eggheadcafe.com/tutorials/aspnet/9cbb4841-8677-49e9-a3a8-46031e699b2e/wpf-printing-and-print-preview.aspx
			//http://blogs.msdn.com/b/fyuan/archive/2007/03/10/convert-xaml-flow-document-to-xps-with-style-multiple-page-page-size-header-margin.aspx
			//http://www.switchonthecode.com/tutorials/printing-in-wpf


			//http://msdn.microsoft.com/en-us/library/ms748373.aspx

			var pdlg = new PrintDialog();

			SelectedPrinter.DefaultPrintTicket.CopyCount = Copies;
			SelectedPrinter.CurrentJobSettings.CurrentPrintTicket.CopyCount = Copies;

			pdlg.PrintQueue = SelectedPrinter;

			var p = GetTemplateChild("PART_PrintPreview") as PrintPreviewItemsControl;
			if (p == null)
				throw new Exception("There is no PrintPreviewItemsControl for printing");

			pdlg.PrintDocument(p.GetDocumentPaginator(), DocumentName);
		}

		#endregion
	}
}
